#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "LevelManager.h"
#include "include.h"
#include "ControlledObject.h"
#include "CpuControlledObject.h"
#include "NpcControlledObject.h"
#include "StateToggleObject.h"
#include "PressureButtonObject.h"
#include "PinnedObject.h"
#include "TranslatingObject.h"
#include "ConditionalTranslatingObject.h"
#include "AbrahamLincoln.h"
#include "Background.h"
#include "ParallaxLayer.h"
#include "Material.h"
#include "GrenadeObject.h"
#include "FrogEnemyObject.h"
#include "Grenade.h"
#include "PickupSprite.h"
#include "Plant.h"
#include "Tentacle.h"
#include "ConditionalStatement.h"
#include "FileReader.h"
#include "NavigationEdgeList.h"
#include "CpuControlledVertibrateObject.h"


LevelManager::LevelManager()
{
}

LevelManager::~LevelManager()
{
	
}
char * LevelManager::GetNextTag(FILE * fptr)
{
	//char * buf = (char *)malloc(sizeof(char) * 
	char c;
	fpos_t startPtr; 
	int startIndex = 0;
	int endIndex = 0;
	int count = 0;
	bool started = false;
	bool ended = false;
	while(fread(&c, sizeof(char), 1, fptr) == 1)
	{
		if(c == '<')
		{
			fgetpos(fptr, &startPtr);
			startIndex = count;
			started = true;
		}
		if(c == '>' && started)
		{
			endIndex = count;
			ended = true;
			break;
		}
		count ++;
	}
	
	if(!started || !ended)
	{
		return NULL;
	}

	fsetpos(fptr, &startPtr);
	fseek(fptr,-1, SEEK_CUR);
	int stringSize = endIndex - startIndex + 1;
	char * buf = (char *) malloc(sizeof(char) * stringSize + 1);
	fread(buf, sizeof(char),stringSize, fptr);
	buf[stringSize] = '\0';
	return buf;
}		

char * LevelManager::GetNextElement(char * tag, int * pos)
{
	if(tag == NULL)
		return NULL;
		
	int startIndex = *pos;
	if(tag[startIndex] == '\0')
		return NULL;
	int endIndex = 0;
	int openparen = 0;
	int stringSize = 0;
	int stringLen = strlen(tag);
	bool closeElement = false;
	for(int i = startIndex; i < stringLen; i++)
	{
		
		if(tag[i] == '<')
			startIndex = i+1;
		if(tag[i] == '(')
			openparen++;
		if(tag[i] == ')' && openparen > 0)
			openparen--;
		if(openparen == 0 && (tag[i] == ',' || tag[i] == '>'))
		{
			endIndex = i - 1;
			*pos = i+1;
			closeElement = true;
			break;
		}
		if(tag[i] == '\0')
			return NULL;
		if(tag[i] != '<' &&tag[i] != ' ' && tag[i] != '\t' && tag[i] != '\n')
		{
			stringSize ++;
		}
	}
	if(!closeElement)
		return NULL;
	char * buf = (char *) malloc(sizeof(char) * stringSize+1);
	int count = 0;
	for(int i = startIndex; i <= endIndex && count < stringSize; i++)
	{
		if(tag[i] != ' ' && tag[i] != '\t' && tag[i] != '\n')
		{
			buf[count] = tag[i];
			count++;
		}
	}
	buf[stringSize] = '\0';
	return buf;
}
int LevelManager::GetMaterialType(char * name)
{
	return materialManager.GetMaterialIndex(name);
}
int LevelManager::GetObjectType(char * name)
{
	if(strcmp(name, "baseobject") == 0)
		return BASE_OBJECT_TYPE;
	if(strcmp(name, "pinnedobject") == 0)
		return PINNED_OBJECT_TYPE;
	if(strcmp(name, "translatingobject") == 0)
		return TRANSLATING_OBJECT_TYPE;
	if(strcmp(name, "conditionaltranslatingobject") == 0)
		return CONDITIONAL_TRANSLATING_OBJECT_TYPE;
	if(strcmp(name, "ropedobject") == 0)
		return ROPED_OBJECT_TYPE;
	if(strcmp(name, "npcobject") == 0)
		return NPC_OBJECT_TYPE;
	if(strcmp(name, "toggleobject") == 0)
		return TOGGLE_OBJECT_TYPE;
	if(strcmp(name, "pressureobject") == 0)
		return PRESSURE_OBJECT_TYPE;
	return UNKNOWN_TYPE;	
}
int LevelManager::GetElementType(char * name)
{
	if(strcmp(name, "border") == 0)
		return BORDER_TYPE;
	else if(strcmp(name, "player") == 0)
		return PLAYER_TYPE;
	else if(strcmp(name, "object") == 0)
		return OBJECT_TYPE;
	else if(strcmp(name, "character") == 0)
		return CHARACTER_TYPE;
	else if(strcmp(name, "enemy") == 0)
		return ENEMY_TYPE;
	else if(strcmp(name, "background") == 0)
		return BACKGROUND_TYPE;
	else if(strcmp(name, "material") == 0)
		return MATERIAL_TYPE;
	else if(strcmp(name, "pickup") == 0)
		return PICKUP_TYPE;
	return UNKNOWN_TYPE;
}
int LevelManager::GetEnemyType(char * name)
{
	printf("checking enemy type- *%s*\n", name);
	if(strcmp(name, "basicenemy") == 0)
		return BASIC_ENEMY_TYPE;
	if(strcmp(name, "frog") == 0)
		return FROG_ENEMY_TYPE;
	if(strcmp(name, "flower") == 0)
		return FLOWER_ENEMY_TYPE;
	return UNKNOWN_TYPE;	
}
int LevelManager::GetCharacterType(char * name)
{
	if(strcmp(name, "base") == 0)
		return BASIC_CHARACTER_TYPE;
	return UNKNOWN_TYPE;
}
float LevelManager::ReadFloat(char * element)
{
	float num;
	if(sscanf(element, "%f", &num)!= 1)
	{
		printf("Error reading float %s\n", element);
	}
	return num;
}
int LevelManager::ReadInt(char * element)
{
	int num;
	if(sscanf(element, "%d", &num)!= 1)
	{
		printf("Error reading integer %s\n", element);
	}
	return num;
}
Vector2D LevelManager::ReadNextCoordinate(char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	Vector2D c = ReadCoordinate(element);
	if(element != NULL)
		free(element);
	element = NULL;
	return c;
}
int LevelManager::ReadNextInt(char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	int i = ReadInt(element);
	if(element != NULL)
		free(element);
	element = NULL;
	return i;
}
float LevelManager::ReadNextFloat(char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	float f = ReadFloat(element);
	if(element != NULL)
		free(element);
	element = NULL;
	return f;
}
char * LevelManager::ReadNextString( char * tag, int * pos)
{
	char * element = GetNextElement(tag, pos);
	return element;
}
Material * LevelManager::ReadNextMaterial(char * tag, int * pos)
{
	char * element = ReadNextString(tag, pos);
	int materialType = GetMaterialType(element);

	if(element != NULL)
		free(element);
	element = NULL;
	
	if(materialType != UNKNOWN_TYPE)
	{
		return materialManager.GetMaterial(materialType);
	}
	else
	{	
		return NULL;
	}
}
Vector2D * LevelManager::ReadNextVectorArray(int numVertices, char * tag, int * pos)
{
	Vector2D * vertices = (Vector2D *)malloc(sizeof(Vector2D) * numVertices);
	assert(vertices != NULL);
	for(int i = 0; i < numVertices; i++)
	{
		vertices[i] = ReadNextCoordinate(tag, pos);
	}
	return vertices;
}
Rope * LevelManager::ReadNextRope(char * tag, int * pos)
{	
	Vector2D position = ReadNextCoordinate(tag, pos);
	int numSegments = ReadNextInt(tag, pos);
	float length = ReadNextFloat(tag, pos);
	float mass = ReadNextFloat(tag, pos);
	float stringConstant = ReadNextFloat(tag, pos);
	
	return new Rope(new Vector2D(position.x, position.y), numSegments, length, mass, stringConstant);
}
ParallaxLayer LevelManager::ReadNextParallaxLayer(char * tag, int * pos)
{
	printf("Reading next parallax layer\n");
	char * textureFile = ReadNextString(tag, pos);
	printf("texture file = %s\n", textureFile);
	Vector2D scrollRatio = ReadNextCoordinate(tag, pos);
	Vector2D size = ReadNextCoordinate(tag, pos);
	Vector2D position = ReadNextCoordinate(tag, pos);
	Vector2D boxSize = ReadNextCoordinate(tag, pos);
	Vector2D boxPosition = ReadNextCoordinate(tag, pos);
	
	ParallaxLayer pl = ParallaxLayer(&textureManager, textureFile, scrollRatio,size,position,boxSize,boxPosition);
	printf("ParallaxLayer created\n");
	
	return pl; 
}
Vector2D LevelManager::ReadCoordinate(char * element)
{
	Vector2D coord;
	if(sscanf(element, "(%f,%f)", &(coord.x), &(coord.y))!= 2)
	{
		printf("Error reading coordinate %s\n", element);
	}
	return coord;
}
void LevelManager::HandleBorderTag( Border ** border, char * tag, int pos)
{

	int elementCount = 0;
	char * element;
	Vector2D * borderVertices = NULL;
	int coordCount = 0;
	int numPoints;
	while((element = GetNextElement(tag, &pos)) != NULL)
	{
		printf("ELEMENT: %s\n", element);
		if(elementCount == 0)
		{
			if(sscanf(element, "%d", &numPoints) != 1)
			{
				printf("Error reading border tag element = %s\n", element);
				return;
			}
			printf("numPoints = %d\n", numPoints);
			borderVertices = (Vector2D *)malloc(numPoints*sizeof(Vector2D));
			
		}
		else
		{
			Vector2D coord = ReadCoordinate(element);
			printf("Coord %d = (%f, %f)\n", coordCount, coord.x, coord.y);
			borderVertices[coordCount] = coord;
			coordCount ++; 
			
		}
		if(element != NULL)
			free(element);
		element = NULL;
		elementCount++;
	}
	if(element != NULL)
		free(element);
	element = NULL;
	*border = new Border(borderVertices, numPoints, &textureManager);
}
int LevelManager::GetPickupType(char * name)
{	
	printf("*%s* type\n", name);
	if(strcmp(name, "grenade")== 0)
		return GRENADE_PICKUP_TYPE;
	return UNKNOWN_TYPE;	
}
void LevelManager::HandleGrenadeTag(SpriteList ** spriteList, char * tag, int pos)
{
	Vector2D position = ReadNextCoordinate(tag, &pos);
	printf("grenade position = (%f, %f)\n", position.x, position.y);
	float mass = ReadNextFloat(tag, &pos);
	float fuseTime = ReadNextFloat(tag, &pos)/10.0;
	float strength = ReadNextFloat(tag, &pos);
	bool explodeOnContact = ReadNextInt(tag, &pos) > 0;
	bool isArmed = ReadNextInt(tag, &pos) > 0;
	Vector2D * texVertices = (Vector2D*)malloc(sizeof(Vector2D)*4);
	texVertices[0] = Vector2D(-0.5,0.5);
	texVertices[1] = Vector2D(0.5,0.5);
	texVertices[2] = Vector2D(0.5,-0.5);
	texVertices[3] = Vector2D(-0.5,-0.5);
	PickupSprite * grenade = new PickupSprite(&textureManager, GRENADE_TEXTURE, texVertices, position, Vector2D(4,4), -1, GRENADE_PICKUP_TYPE);
	
	if(!(*spriteList))
		(*spriteList) = new SpriteList(grenade);
	else
		(*spriteList)->Add(grenade);
	/*GrenadeObject * grenade = new GrenadeObject(&textureManager, position, Vector2D(0,0), Vector2D(0,0), 0.0, 0.0, 0.0,
												mass, fuseTime, strength, explodeOnContact, isArmed);
	printf("adding grenade\n");
	if(!(*objectList))
		(*objectList) = new ObjectList(grenade);
	else
		(*objectList)->Add(grenade);*/
}
void LevelManager::HandlePickupTag(SpriteList ** spriteList, char * tag, int pos)
{
	
	printf("checking pickup tag\n");
	char * element;
	
	element = GetNextElement(tag, &pos);
	
	if(element != NULL)
	{
		int type = GetPickupType(element);
		printf("element = %s, type = %d\n", element, type);
		switch(type)
		{
			case GRENADE_PICKUP_TYPE:
				HandleGrenadeTag(spriteList,tag, pos);
				break;
			case UNKNOWN_TYPE:
			default:
				printf("Unknown pickup type - %s\n", element);
			break;
		}
		free(element);
		element = NULL;
	}
}

void LevelManager::HandleEnemyTag(ObjectList ** objectList, AbrahamLincoln * player, char * tag, int pos)
{
	printf("checking enemy tag\n");
	char * element;
	
	element = GetNextElement(tag, &pos);
	
	if(element != NULL)
	{
		int type = GetEnemyType(element);
		printf("element = %s, type = %d\n", element, type);
		switch(type)
		{
			case BASIC_ENEMY_TYPE:
				HandleBasicEnemyTag(objectList, player, tag, pos);
				break;
			case FROG_ENEMY_TYPE:
				HandleFrogEnemyTag(objectList, player, tag, pos);
				break;
			case FLOWER_ENEMY_TYPE:
				HandleFlowerEnemyTag(objectList, player, tag, pos);
				break;
			case UNKNOWN_TYPE:
			default:
				printf("Unknown enemy type - %s\n", element);
			break;
		}
		free(element);
		element = NULL;
	}
}
void LevelManager::HandleBasicEnemyTag(ObjectList ** objectList, AbrahamLincoln * player, char * tag, int pos)
{
	char * element;
	printf("Handling basic enemy\n");
	element = GetNextElement(tag, &pos);

	if(element != NULL)
	{
		printf("Element: %s\n", element);
		Vector2D position = ReadCoordinate(element);
		
		free(element);
		element = NULL;
		
		element = GetNextElement(tag, &pos);
		
		if(element != NULL)
		{
			printf("Element: %s\n", element);
			float mass = ReadFloat(element);
		
			free(element);
			element = NULL;
		
			CpuControlledObject * enemy = new CpuControlledObject( &textureManager,
						 									   		position,
						 									   		mass,
						 									   		(player));
			if((*objectList) == NULL)
			{
				(*objectList) = new ObjectList(enemy);
			}
			else
			{
				(*objectList)->Add(enemy);
			}
		}
	}
}
void LevelManager::HandleFlowerEnemyTag(ObjectList ** objectList, AbrahamLincoln * player, char * tag, int pos)
{
	char * element;
	printf("Handling flower enemy\n");
	element = GetNextElement(tag, &pos);

	if(element != NULL)
	{
		printf("Element: %s\n", element);
		Vector2D position = ReadCoordinate(element);
		
		free(element);
		element = NULL;
		
		element = GetNextElement(tag, &pos);
		
		if(element != NULL)
		{
			printf("Element: %s\n", element);
			Vector2D direction = ReadCoordinate(element);
		
			free(element);
			element = NULL;
			float length = ReadNextFloat(tag, &pos);
			float size = ReadNextFloat(tag, &pos);
			float mass = ReadNextFloat(tag, &pos);
		
			Vector2D textureVertices[4] = //(Vector2D *)malloc(sizeof(Vector2D)*4);
			{Vector2D(0,0), Vector2D(0,1), Vector2D(1,1),  Vector2D(1,0)};
			Vector2D textureVertices2[4] = //(Vector2D *)malloc(sizeof(Vector2D)*4);
			{Vector2D(1,0), Vector2D(1,1),  Vector2D(0,1), Vector2D(0,0)};
			Vector2D * textureVertices3 = (Vector2D *)malloc(sizeof(Vector2D)*4);
			textureVertices3[0] = Vector2D(0,1);
			textureVertices3[1] = Vector2D(1,1);
			textureVertices3[2] = Vector2D(1,0);
			textureVertices3[3] = Vector2D(0,0);
			
			
			Vector2D rootPosition = Vector2D(30,10);
			Tentacle * tentacles = (Tentacle *)malloc(sizeof(Tentacle)*2);
			tentacles[0] = Tentacle(&textureManager, TENTACLE_TEXTURE, textureVertices, 15, position, Vector2D(5,5));
			tentacles[1] = Tentacle(&textureManager, TENTACLE_TEXTURE, textureVertices2, 15, position, Vector2D(-5,5));
			
			
			Plant * enemy = new Plant(&textureManager,
										FLOWER_TEXTURE,
										textureVertices3,
										position, 
										direction,
										length,
										size,
										mass,
										2,
										tentacles);
			if((*objectList) == NULL)
			{
				(*objectList) = new ObjectList(enemy);
			}
			else
			{
				(*objectList)->Add(enemy);
			}
		}
	}
}
void LevelManager::HandleFrogEnemyTag(ObjectList ** objectList, AbrahamLincoln * player, char * tag, int pos)
{
	char * element;
	printf("Handling frog enemy\n");
	element = GetNextElement(tag, &pos);

	if(element != NULL)
	{
		printf("Element: %s\n", element);
		Vector2D position = ReadCoordinate(element);
		
		free(element);
		element = NULL;
		
		element = GetNextElement(tag, &pos);
		
		if(element != NULL)
		{
			printf("Element: %s\n", element);
			float mass = ReadFloat(element);
		
			free(element);
			element = NULL;
		
			FrogEnemyObject * enemy = new FrogEnemyObject( &textureManager,
						 									   		position,
						 									   		mass,
						 									   		(player));
			if((*objectList) == NULL)
			{
				(*objectList) = new ObjectList(enemy);
			}
			else
			{
				(*objectList)->Add(enemy);
			}
		}
	}
}
void LevelManager::HandleCharacterTag(ObjectList ** objectList, AbrahamLincoln * player, char * tag, int pos)
{
	char * element;
	
	element = GetNextElement(tag, &pos);
	
	if(element != NULL)
	{
		int type = GetCharacterType(element);
		
		switch(type)
		{
			case BASIC_CHARACTER_TYPE:
				HandleBasicCharacterTag(objectList, player, tag, pos);
				break;
			
			case UNKNOWN_TYPE:
			default:
				printf("Unknown object type - %s\n", element);
				break;
		}
		free(element);
		element = NULL;
	}
}
void LevelManager::HandleBasicCharacterTag(ObjectList ** objectList, AbrahamLincoln * player, char * tag, int pos)
{
	printf("LevelManager::HandleBasicCharacterTag\n");
	Vector2D position = ReadNextCoordinate(tag, &pos);
	char * skeletonFile = ReadNextString(tag, &pos);
	bool isGrabbable = ReadNextInt(tag, &pos) > 0;
	int numEdges = ReadNextInt(tag, &pos);
	NavigationEdgeList * list = new NavigationEdgeList();
	for(int i = 0; i < numEdges; i++)
	{
		printf("loop %d\n", i);
		NavigationEdge * edge = FileReader::ReadNextNavigationEdge(tag, &pos);
		if(edge)
			list->Add(edge);
	}
	printf("HERE\n");
	Vector2D * vertices = (Vector2D *)malloc(sizeof(Vector2D)*4);
	vertices[0] = Vector2D(-3,3);
	vertices[1] = Vector2D(3,3);
	vertices[2] = Vector2D(3,-3);
	vertices[3] = Vector2D(-3,-3);
	CpuControlledVertibrateObject * object = new CpuControlledVertibrateObject(&textureManager,
					 			  											   position,
					  			  vertices, 4, 1.0, isGrabbable, skeletonFile,list);
	printf("HERE2\n");
	if(*objectList)
	{
		(*objectList)->Add(object);
	}
	else
	{
		(*objectList) = new ObjectList(object);	
	}
}
	
void LevelManager::HandleObjectTag(Dictionary * gameState, ObjectList ** objectList, ObjectList ** featureList, StringList ** stringList, char * tag, int pos)
{
	char * element;
	
	element = GetNextElement(tag, &pos);
	
	if(element != NULL)
	{
		int type = GetObjectType(element);
		
		switch(type)
		{
			case BASE_OBJECT_TYPE:
				HandleBaseObjectTag(objectList, featureList, tag, pos);
				break;
			case PINNED_OBJECT_TYPE:
				HandlePinnedObjectTag(objectList, tag, pos);
				break;
			case TRANSLATING_OBJECT_TYPE:
				HandleTranslatingObjectTag(objectList, tag, pos);
				break;
			case CONDITIONAL_TRANSLATING_OBJECT_TYPE:
				HandleConditionalTranslatingObjectTag(gameState, objectList, tag, pos);
				break;
			case ROPED_OBJECT_TYPE:
				HandleRopedObjectTag(objectList, stringList, tag, pos);
				break;
			case NPC_OBJECT_TYPE:
				HandleNpcObjectTag(objectList, tag, pos);
				break;
			case TOGGLE_OBJECT_TYPE:
				HandleToggleObjectTag(gameState, objectList, tag, pos);
				break; 
			case PRESSURE_OBJECT_TYPE:
				HandlePressureButtonObjectTag(gameState, objectList, tag, pos);
				break;
			case UNKNOWN_TYPE:
			default:
				printf("Unknown object type - %s\n", element);
				break;
		}
		free(element);
		element = NULL;
	}
}
void LevelManager::HandlePinnedObjectTag(ObjectList ** objectList, char * tag, int pos)
{
	int elementCount = 0;
	char * element;
	Vector2D position;
	int numVertices = 0;
	Vector2D * vertices = NULL;
	Vector2D pinPoint;
	Material * material;
	float mass;
	float textureRotation;
	while((element = GetNextElement(tag, &pos)) != NULL)
	{
		printf("ELEMENT: %s\n", element);
		if(elementCount == 0)
		{
			int materialType = GetMaterialType(element);

			if(materialType != UNKNOWN_TYPE)
			{
				material = materialManager.GetMaterial(materialType);
			}
			else
			{
				printf("Unknown material - %s\n", element);
				if(element != NULL)
					free(element);
				element = NULL;
				return;
			}
		}
		else if(elementCount == 1)
		{
			textureRotation = ReadFloat(element);
		}
		else if(elementCount == 2)
		{
			numVertices = ReadInt(element);
			vertices = (Vector2D *)malloc(sizeof(Vector2D) * numVertices);
			assert(vertices != NULL);
		}
		else if(elementCount <= numVertices + 2)
		{
			vertices[elementCount - 3] = ReadCoordinate(element);
		}
		else if(elementCount == numVertices + 3)
		{
			position = ReadCoordinate(element);
		}
		else if(elementCount == numVertices + 4)
		{
			pinPoint = ReadCoordinate(element);
		}
		else if(elementCount == numVertices + 5)
		{
			mass = ReadFloat(element);
		}
		
		
		if(element != NULL)
			free(element);
		element = NULL;
		elementCount++;
	}
	PinnedObject * pinnedObject = new PinnedObject( &textureManager,
													 material,
													 textureRotation,
													 position, 
													 Vector2D(0,0),
													 Vector2D(0,0),
													 vertices,
													 numVertices,
													 0.0f,
													 0.0f,
													 0.0f,
													 mass,
													 false,
													 pinPoint);
	if((*objectList) == NULL)
	{
		(*objectList) = new ObjectList(pinnedObject);
	}
	else
	{
		(*objectList)->Add(pinnedObject);
	}
}
void LevelManager::HandleConditionalTranslatingObjectTag(Dictionary * gameState, ObjectList ** objectList, char * tag, int pos)
{
	printf("LevelManager::HandleConditionalTranslatingObjectTag\n");
	ConditionalStatement * conditionalStatement = FileReader::ReadNextConditionalStatement(tag, &pos);
	Material * material = ReadNextMaterial(tag, &pos);
	float textureRotation = ReadNextFloat(tag, &pos);
	int numVertices = ReadNextInt(tag, &pos);
	Vector2D * vertices = ReadNextVectorArray(numVertices, tag, &pos);
	float speed = ReadNextFloat(tag, &pos);
	float mass = ReadNextFloat(tag, &pos);
	int numPath = ReadNextInt(tag, &pos);
	Vector2D * path = ReadNextVectorArray(numPath, tag, &pos);
	printf("Making object\n");
	ConditionalTranslatingObject * conditionalTranslatingObject =
					 new ConditionalTranslatingObject(	gameState,
														&textureManager,
														conditionalStatement,
														material,
														textureRotation,
														vertices,
														numVertices,
														mass,
														path,
														numPath,
														speed);
	if((*objectList) == NULL)
	{
		(*objectList) = new ObjectList(conditionalTranslatingObject);
	}
	else
	{
		(*objectList)->Add(conditionalTranslatingObject);
	}
	
}
void LevelManager::HandleTranslatingObjectTag(ObjectList ** objectList, char * tag, int pos)
{
	int elementCount = 0;
	char * element;
	int numVertices = 0;
	Vector2D * vertices = NULL;
	int numPath = 0;
	Vector2D * path = NULL;
	Material * material;
	float mass;
	float textureRotation;
	float speed;
	while((element = GetNextElement(tag, &pos)) != NULL)
	{
		printf("ELEMENT: %s\n", element);
		if(elementCount == 0)
		{
			int materialType = GetMaterialType(element);

			if(materialType != UNKNOWN_TYPE)
			{
				material = materialManager.GetMaterial(materialType);
			}
			else
			{
				printf("Unknown material - %s\n", element);
				if(element != NULL)
					free(element);
				element = NULL;
				return;
			}
		}
		else if(elementCount == 1)
		{
			textureRotation = ReadFloat(element);
		}
		else if(elementCount == 2)
		{
			numVertices = ReadInt(element);
			vertices = (Vector2D *)malloc(sizeof(Vector2D) * numVertices);
			assert(vertices != NULL);
		}
		else if(elementCount <= numVertices + 2)
		{
			vertices[elementCount - 3] = ReadCoordinate(element);
		}
		else if(elementCount == numVertices + 3)
		{
			speed = ReadFloat(element);
		}
		else if(elementCount == numVertices + 4)
		{
			mass = ReadFloat(element);
		}
		else if(elementCount == numVertices + 5)
		{
			numPath = ReadInt(element);
			path = (Vector2D *)malloc(sizeof(Vector2D) * numPath);
			assert(path != NULL);
		}
		else if( elementCount <= numVertices + numPath + 5)
		{
			path[elementCount - numVertices - 6] = ReadCoordinate(element);
		}
		
		
		if(element != NULL)
			free(element);
		element = NULL;
		elementCount++;
	}
	TranslatingObject * translatingObject = new TranslatingObject(	&textureManager,
														material,
														textureRotation,
														vertices,
														numVertices,
														mass,
														path,
														numPath,
														speed);
	if((*objectList) == NULL)
	{
		(*objectList) = new ObjectList(translatingObject);
	}
	else
	{
		(*objectList)->Add(translatingObject);
	}
}
void LevelManager::HandleMaterialTag(char * tag, int pos)
{
	//Material(float bounciness, float friction, bool isGrabbable, float textureSize, int textureIndex);
	
	char * materialName = ReadNextString(tag, &pos);
	char * file = ReadNextString(tag, &pos);
	float bounciness = ReadNextFloat(tag, &pos);
	float friction = ReadNextFloat(tag, &pos);
	bool isGrabbable = ReadNextInt(tag, &pos) > 0;
	float size = ReadNextFloat(tag, &pos);
	
	if(!textureManager.LoadTexture(file))
		printf("Failed to load %s\n", file);
	materialManager.Add(new Material(materialName, bounciness, friction, isGrabbable, size, textureManager.TextureIndex(file)));
	
		
}
void LevelManager::HandleBackgroundTag(Camera ** camera, char * tag, int pos)
{
	
	char * backgroundFile = ReadNextString(tag, &pos);
	int numLayers = ReadNextInt(tag, &pos);
	
	ParallaxLayer * layers = (ParallaxLayer *)malloc(sizeof(ParallaxLayer) * numLayers);
	assert(layers != NULL);
	for(int i = 0; i < numLayers; i++)
	{
		layers[i] = ReadNextParallaxLayer(tag, &pos);
	}
	
	printf("Making background\n");
	(*camera)->SetBackground(new Background(&textureManager, backgroundFile, layers, numLayers));
	printf("Background made\n");
}
void LevelManager::HandleNpcObjectTag(ObjectList ** objectList, char * tag, int pos)
{

	char * name = ReadNextString(tag, &pos);
	char * texture = ReadNextString(tag, &pos);
	char * dialogue = ReadNextString(tag, &pos);
	int numVertices = ReadNextInt(tag, &pos);
	Vector2D * vertices = ReadNextVectorArray(numVertices, tag, &pos);
	Vector2D position = ReadNextCoordinate(tag, &pos);
	Vector2D size = ReadNextCoordinate(tag, &pos);
	float mass = ReadNextFloat(tag, &pos);
	
	NpcControlledObject * npc = new NpcControlledObject(&textureManager, texture, position, vertices, numVertices,
														mass, size, dialogue, name);
	
	printf("Adding NPC object\n");
	if((*objectList) == NULL)
	{
		(*objectList) = new ObjectList(npc);
	}
	else
	{
		(*objectList)->Add(npc);
	}	
}
void LevelManager::HandlePressureButtonObjectTag(Dictionary * gameState, ObjectList ** objectList, char * tag, int pos)
{
	char * name = ReadNextString(tag, &pos);
	int numVertices = ReadNextInt(tag, &pos);
	Vector2D * vertices = ReadNextVectorArray(numVertices, tag, &pos);
	Vector2D position = ReadNextCoordinate(tag, &pos);
	float mass = ReadNextFloat(tag, &pos);
	bool isGrabbable = ReadNextInt(tag, &pos) > 0;	
	Vector2D movementAxis = ReadNextCoordinate(tag, &pos);
	Vector2D movementEndpoints = ReadNextCoordinate(tag, &pos);
	bool offRight = ReadNextInt(tag, &pos) > 0;	
	bool sticky = ReadNextInt(tag, &pos) > 0;	
	float springConstant = ReadNextFloat(tag, &pos);				
	char * textureName = ReadNextString(tag, &pos);
	Vector2D * textureVertices = ReadNextVectorArray(numVertices, tag, &pos);
	
	PressureButtonObject * object = new PressureButtonObject(name, &textureManager, gameState,
					position,vertices,numVertices,mass,isGrabbable,movementAxis,movementEndpoints,
					offRight,sticky,springConstant,textureName,textureVertices);

	printf("Adding  Button object\n");
	if((*objectList) == NULL)
	{
		(*objectList) = new ObjectList(object);
	}
	else
	{
		(*objectList)->Add(object);
	}
	
}
void LevelManager::HandleToggleObjectTag(Dictionary * gameState, ObjectList ** objectList, char * tag, int pos)
{
	char * name = ReadNextString(tag, &pos);
	bool isActive = ReadNextInt(tag, &pos) > 0;
	bool isGrabbable = ReadNextInt(tag, &pos) > 0;
	bool flipOnce = ReadNextInt(tag, &pos) > 0;
	float transitionTime = ReadNextFloat(tag, &pos);
	
	Vector2D inactivePosition = ReadNextCoordinate(tag, &pos);
	int numInactiveVertices = ReadNextInt(tag, &pos);
	Vector2D * inactiveVertices = ReadNextVectorArray(numInactiveVertices, tag, &pos);
	char * inactiveTextureName = ReadNextString(tag, &pos);
	Vector2D * inactiveTextureVertices = ReadNextVectorArray(numInactiveVertices, tag, &pos);
	
	Vector2D activePosition = ReadNextCoordinate(tag, &pos);
	int numActiveVertices = ReadNextInt(tag, &pos);
	Vector2D * activeVertices = ReadNextVectorArray(numActiveVertices, tag, &pos);
	char * activeTextureName = ReadNextString(tag, &pos);
	Vector2D * activeTextureVertices = ReadNextVectorArray(numActiveVertices, tag, &pos);
	
	
	
	StateToggleObject * object = new StateToggleObject( name, &textureManager, gameState, 
					   							    isActive, isGrabbable, flipOnce,
					   								inactivePosition, inactiveVertices, numInactiveVertices,
					   								activePosition, activeVertices, numActiveVertices, transitionTime,
					   								inactiveTextureName, inactiveTextureVertices, 
					   								activeTextureName, activeTextureVertices); 
					   
	printf("Adding State Toggle object\n");
	if((*objectList) == NULL)
	{
		(*objectList) = new ObjectList(object);
	}
	else
	{
		(*objectList)->Add(object);
	}
}
void LevelManager::HandleRopedObjectTag(ObjectList ** objectList, StringList ** stringList, char * tag, int pos)
{
	//get the material
	Material * material = ReadNextMaterial(tag, &pos);
	float textureRotation = ReadNextFloat(tag, &pos);
	int numVertices = ReadNextInt(tag, &pos);
	Vector2D * vertices = ReadNextVectorArray(numVertices, tag, &pos);
	Vector2D position = ReadNextCoordinate(tag, &pos);
	float mass = ReadNextFloat(tag, &pos);
	int numStrings = ReadNextInt(tag, &pos);
	Vector2D * connectionPoint = ReadNextVectorArray(numStrings, tag, &pos);
	Rope ** strings = (Rope **)malloc(sizeof(Rope*) * numStrings);
	
	
	Object * object = new Object( &textureManager,
								  material,
								  textureRotation,
								  position, 
								  Vector2D(0,0),
								  Vector2D(0,0),
								  vertices,
								  numVertices,
								  0.0f,
								  0.0f,
								  0.0f,
								  mass,
								  false);
								  
	for(int i = 0; i < numStrings; i++)
	{
		strings[i] = ReadNextRope(tag, &pos);	
		Vector2D * location = new Vector2D(connectionPoint[i].x, connectionPoint[i].y);
		object->AddKeyPoint(location);	
		strings[i]->Grab(object, location);
		
		if((*stringList) == NULL)
		{
			(*stringList) = new StringList(strings[i]);
		}
		else
		{
			(*stringList)->Add(strings[i]);
		}
	}
	
	if(connectionPoint != NULL)
		free(connectionPoint);
	connectionPoint = NULL;
								  
	printf("Adding roped object\n");
	if((*objectList) == NULL)
	{
		(*objectList) = new ObjectList(object);
	}
	else
	{
		(*objectList)->Add(object);
	}
	
}
void LevelManager::HandleBaseObjectTag(ObjectList ** objectList, ObjectList ** featureList, char * tag, int pos)
{
	int elementCount = 0;
	char * element;
	Vector2D position;
	int numVertices = 0;
	Vector2D * vertices = NULL;
	bool frozen;
	Material * material;
	float mass;
	float textureRotation;
	while((element = GetNextElement(tag, &pos)) != NULL)
	{
		printf("ELEMENT: %s\n", element);
		if(elementCount == 0)
		{
			int materialType = GetMaterialType(element);

			if(materialType != UNKNOWN_TYPE)
			{
				material = materialManager.GetMaterial(materialType);
			}
			else
			{
				printf("Unknown material - %s\n", element);
				if(element != NULL)
					free(element);
				element = NULL;
				return;
			}
		}
		else if(elementCount == 1)
		{
			textureRotation = ReadFloat(element);
		}
		else if(elementCount == 2)
		{
			numVertices = ReadInt(element);
			vertices = (Vector2D *)malloc(sizeof(Vector2D) * numVertices);
			assert(vertices != NULL);
		}
		else if(elementCount <= numVertices + 2)
		{
			vertices[elementCount - 3] = ReadCoordinate(element);
		}
		else if(elementCount == numVertices + 3)
		{
			position = ReadCoordinate(element);
		}
		else if(elementCount == numVertices + 4)
		{
			frozen = ReadInt(element) > 0;
		}
		else if(elementCount == numVertices + 5)
		{
			mass = ReadFloat(element);
		}
		
		
		if(element != NULL)
			free(element);
		element = NULL;
		elementCount++;
	}
							 
	Object * object = new Object( &textureManager,
								  material,
								  textureRotation,
								  position, 
								  Vector2D(0,0),
								  Vector2D(0,0),
								  vertices,
								  numVertices,
								 0.0f,
								 0.0f,
								 0.0f,
								 mass,
								 frozen);
								 
	if(!frozen)
	{
		printf("Adding object\n");
		if((*objectList) == NULL)
		{
			(*objectList) = new ObjectList(object);
		}
		else
		{
			(*objectList)->Add(object);
		}
	}
	else
	{
		printf("Adding frozen object\n");
		if((*featureList) == NULL)
		{
			(*featureList) = new ObjectList(object);
		}
		else
		{
			(*featureList)->Add(object);
		}
	}
}
void LevelManager::HandlePlayerTag(Camera ** camera, AbrahamLincoln ** player, SupplyBag * supplyBag, char * tag, int pos)
{
	int elementCount = 0;
	char * element;
	Vector2D position;
	while((element = GetNextElement(tag, &pos)) != NULL)
	{
		printf("ELEMENT: %s\n", element);
		if(elementCount == 0)
		{
			position = ReadCoordinate(element);
			printf("Coord = (%f, %f)\n", position.x, position.y);
			
		}
		if(element != NULL)
			free(element);
		element = NULL;
		elementCount++;
	}
	if(element != NULL)
		free(element);
	element = NULL;
	
	if((*player) == NULL)
	{
		printf("Player position = (%f, %f)\n", position.x, position.y);
		(*player) = new AbrahamLincoln( supplyBag, &textureManager,
									 position, 1.0);
		printf("GameManager::Player created\n");
	}
	else
	{
		(*player)->position = position;
		(*player)->SetHealth(PLAYER_MAX_HEALTH);
	}
	(*camera)->SetFocusObject((*player),true);

}
void LevelManager::LoadLevel(const char * fileName, Dictionary * gameState, AbrahamLincoln ** player, Camera ** camera, Border ** border, ObjectList ** objectList, ObjectList ** featureList, StringList ** stringList, SpriteList ** spriteList, SupplyBag * supplyBag)
{

	
	char longFileName[250] = "./Levels/";
	strcat(longFileName,fileName);
	
	FILE * fptr = NULL;
	if((fptr = fopen(longFileName, "r")) == NULL)
	{
		printf("Error opening level -%s-\n", fileName);
	}
	
	char * tag;
	while((tag = GetNextTag(fptr)) != NULL)
	{
		printf("TAG: %s\n", tag);
		//read through the tag, one element at a time
		int pos = 0;		
		char * element = GetNextElement(tag, &pos);
		
		printf("ELEMENT: %s\n", element);
		//this is the tag's name. Use this to decide how to handle
		//the other parameters
		
		switch(GetElementType(element))
		{
			case BORDER_TYPE: 
				HandleBorderTag(border, tag, pos);
				break;
			case PLAYER_TYPE:
				HandlePlayerTag(camera, player, supplyBag, tag, pos);
				break;
			case OBJECT_TYPE:
				HandleObjectTag(gameState, objectList, featureList, stringList, tag, pos);
				break;
			case ENEMY_TYPE:
				HandleEnemyTag(objectList, (*player), tag, pos);
				break;
			case CHARACTER_TYPE:
				HandleCharacterTag(objectList, (*player), tag, pos);
				break;
			case PICKUP_TYPE:
				HandlePickupTag(spriteList, tag, pos);
				break;
			case BACKGROUND_TYPE:
				HandleBackgroundTag(camera, tag, pos);
				break;
			case MATERIAL_TYPE:
				HandleMaterialTag(tag, pos);
				break;
		}
			
		if(element != NULL)
			free(element);
		element = NULL;
		if(tag != NULL)
			free(tag);
		tag = NULL;
	}
	fclose(fptr);
	
	if(*(objectList) == NULL)
		(*objectList) = new ObjectList(*player);
	else
		(*objectList)->Add(*player);
	
}
